package org.tulkas.web;

import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;

/**
 * @author <a href="mailto:tulkas.web@gmail.com">Tulkas</a>
 *
 */
public class TulkasHandlerExceptionResolver extends
		DefaultHandlerExceptionResolver {
	private static Logger logger = LoggerFactory
			.getLogger(TulkasHandlerExceptionResolver.class);

	@Override
	protected ModelAndView doResolveException(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex) {
		ModelAndView mav = super.doResolveException(request, response, handler,
				ex);
		if (mav == null) {
			try {
				if (ex instanceof RequestException) {
					response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex
							.getMessage());
				} else {
					response.sendError(
							HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
							"Please check server log at time ["
									+ DateFormat.getDateTimeInstance().format(
											new Date()) + "]");
					logger.error(ex.getMessage(), ex);
				}
			} catch (IOException e) {
				logger.warn(e.getMessage(), e);
			}
			mav = new ModelAndView();
		}
		request.setAttribute("error_referer", request.getHeader("referer"));
		return mav;
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleNoSuchRequestHandlingMethod(org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleNoSuchRequestHandlingMethod(
			NoSuchRequestHandlingMethodException ex,
			HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
		response.sendError(HttpServletResponse.SC_NOT_FOUND, ex.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleHttpMediaTypeNotSupported(org.springframework.web.HttpMediaTypeNotSupportedException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleHttpMediaTypeNotSupported(
			HttpMediaTypeNotSupportedException ex, HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, ex
				.getMessage());
		List<MediaType> mediaTypes = ex.getSupportedMediaTypes();
		if (!CollectionUtils.isEmpty(mediaTypes)) {
			response.setHeader("Accept", MediaType.toString(mediaTypes));
		}
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleHttpMediaTypeNotAcceptable(org.springframework.web.HttpMediaTypeNotAcceptableException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleHttpMediaTypeNotAcceptable(
			HttpMediaTypeNotAcceptableException ex, HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, ex
				.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleMissingServletRequestParameter(org.springframework.web.bind.MissingServletRequestParameterException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleMissingServletRequestParameter(
			MissingServletRequestParameterException ex,
			HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {

		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleConversionNotSupported(org.springframework.beans.ConversionNotSupportedException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleConversionNotSupported(
			ConversionNotSupportedException ex, HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex
				.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleTypeMismatch(org.springframework.beans.TypeMismatchException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleTypeMismatch(TypeMismatchException ex,
			HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleHttpMessageNotReadable(org.springframework.http.converter.HttpMessageNotReadableException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleHttpMessageNotReadable(
			HttpMessageNotReadableException ex, HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
		return new ModelAndView();
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#handleHttpMessageNotWritable(org.springframework.http.converter.HttpMessageNotWritableException, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	protected ModelAndView handleHttpMessageNotWritable(
			HttpMessageNotWritableException ex, HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex
				.getMessage());
		return new ModelAndView();
	}

}
